package crawler;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import structures.InfoPacket;
import structures.TaskType;

//singleton - połaczenie z serwerem od strony klienta
public class CrawlerConnection {
	private Socket _socket;
	private ObjectOutputStream _out = null;
	private ObjectInputStream _in = null;
	private Lock l1 = null;
	private Lock l2 = null;
	private boolean shuttingDown;

	// prywatny konstruktor
	private CrawlerConnection(int port, String address) {
		l1 = new ReentrantLock();
		l2 = new ReentrantLock();
		try {

			_socket = new Socket(address, port);
			_in = new ObjectInputStream(_socket.getInputStream());
			_out = new ObjectOutputStream(_socket.getOutputStream());

		} catch (UnknownHostException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}

	}

	public void shutDown() // motoda uaktywni się, kiedy pierwsszy crawler
							// dostanie task typu shutdown
	{
		if (!shuttingDown) {
			System.out.println("Serwer kończy pracę - kończenie pracy CrawlerConnection");
			shuttingDown = true;
			new Thread(new Runnable() {

				@Override
				public void run() {
					try {
						Thread.sleep(100);		//oczekuje, aż wszsystkie Crawlery się zakończą.
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					// wysli wiadomość typu returnshutdown
					InfoPacket pck = new InfoPacket();
					pck._taskList = new LinkedList<TaskType>();
					pck._taskList.add(TaskType.shutdownReturn);
					pck._taskArguments = new LinkedList<Object>();
					try {
						sendInfoPacket(pck);		//wysyła do wątku odbierającego komunikaty wiadomość o zaknięciu klienta 
						_in.close();
						_out.close();
						_socket.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

				}

			});
		}
	}

	// jedyna instacja klasy
	private static CrawlerConnection instance = null;

	// klasa zwracająca jedyną instancję systemu
	public static CrawlerConnection getConnector(int port, String address) {
		if (instance == null) {
			instance = new CrawlerConnection(port, address);
		}
		return instance;
	}

	// wysyłanie pakietów
	public void sendInfoPacket(InfoPacket packet) throws IOException {
		l1.lock();
		_out.writeObject(packet);
		l1.unlock();
	}

	// odbieranie pakietów
	public InfoPacket receivePacket() throws IOException,
			ClassNotFoundException {
		l2.lock();
		InfoPacket pck = (InfoPacket) _in.readObject();
		//shutdown nie powinien być tutaj?
		l2.unlock();
		return pck;
	}
}
